/**手写promise */
const PENDING = "PENDING";
const RESOLVED = "RESOLVED";
const REJECTED = "REJECTED";
const resolvePromise = (promise2, x, resolve, reject) => {
    if (promise2 === x) {
        return reject(new TypeError("chaining cycle detected for promise"));
    }

    if ((typeof x === "object" && x !== null) || typeof x === "function") {
        let then = x.then; //取出then方法，这个then方法是采用defineProperty定义的
        let called; //一旦掉了成功就不能掉失败，vice versa 为了考虑别人的promise库不健壮
        try {
            if (typeof then === "function") {
                then.call(
                    x,
                    (y) => {
                        if (called) return;
                        called = true;
                        resolvePromise(promise2, y, resolve, reject); //递归解析
                    },
                    (r) => {
                        if (called) return;
                        called = true;
                        reject(r);
                    }
                );
            } else {
                resolve(x);
            }
        } catch (e) {
            if (called) return;
            called = true;
            reject(e);
        }
    } else {
        resolve(x);
    }
};
class Promise {
    constructor(executor) {
        this.status = PENDING;
        this.value = undefined;
        this.reason = undefined;
        this.onResolvedCallbacks = [];
        this.onRejectedCallbacks = [];
        //保证只有状态是等待态的时候才能更改状态
        let resolve = (value) => {
            if (value instanceof Promise) {
                return value.then(resolve, reject);
            }
            if (this.satus === PENDING) {
                this.value = value;
                this.status = RESOLVED;

                //需要让成功的方法依次执行
                this.onResolvedCallbacks.forEach((fn) => fn());
            }
        };
        let reject = (reason) => {
            if (this.status === PENDING) {
                this.reason = reason;
                this.status = REJECTED;

                this.onRejectedCallbacks.forEach((fn) => fn());
            }
        };
        try {
            executor(resolve, reject);
        } catch (e) {
            console.log(e);
            reject(e);
        }
    }
    then(onfulfilled, onrejected) {
        onfulfilled =
            typeof onfulfilled === "function" ? onfulfilled : (val) => val;
        onrejected =
            typeof onrejected === "function"
                ? onrejected
                : (err) => {
                      throw err;
                  };
        let promise2 = new Promise((resolve, reject) => {
            if (this.status === RESOLVED) {
                setTimeout(() => {
                    try {
                        let x = onfulfilled(this.value);
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (e) {
                        reject(e);
                    }
                }, 0);
            }
            if (this.status === REJECTED) {
                setTimeout(() => {
                    try {
                        let x = onrejected(this.reason);
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (e) {
                        reject(e);
                    }
                }, 0);
            }
            if (this.status === PENDING) {
                setTimeout(() => {
                    try {
                        this.onResolvedCallbacks.push(() => {
                            let x = onfulfilled(this.value);
                            resolvePromise(promise2, x, resolve, reject);
                        });
                    } catch (e) {
                        reject(e);
                    }
                }, 0);
                setTimeout(() => {
                    try {
                        this.onRejectedCallbacks.push(() => {
                            let x = onrejected(this.reason);
                            resolvePromise(promise2, x, resolve, reject);
                        });
                    } catch (e) {
                        reject(e);
                    }
                }, 0);
            }
        });
        return promise2;
    }
    catch(errCb) {
        return this.then(null, errCb);
    }
}
//promise.all方法表示等待所有的promise全部成功后才会执行回调，如果有一个promise失败就失败了
const isPromise = (val) => {
    if (
        (typeof val === "object" && val !== null) ||
        typeof val === "function"
    ) {
        return typeof val.then === "function";
    }
    return false;
};

Promise.all = function (promises) {
    return new Promise((resolve, reject) => {
        let result = [];
        let index = 0;
        let len = promises.length;
        if(len === 0) {
            resolve(result);
            return;
        }

        for(let i = 0; i < len; i++) {
            // 为什么不直接 promise[i].then, 因为promise[i]可能不是一个promise
            Promise.resolve(promise[i]).then(data => {
              result[i] = data;
              index++;
              if(index === len) resolve(result);
            }).catch(err => {
              reject(err);
            })
        }
    });
};
// promise.race 谁第一个完成 用它的结果 如果是失败这个promise就失败
//
const isPromise = function (promise) {
    return typeof promise.then === "function";
};
Promise.race = function (promises) {
    return new Promise((resolve,reject)=>{
        let len = promises.length;
        if(len === 0) return;
        for(let i=0;i<len;i++){
           Promise.resolve(promises[i]).then(resolve,reject)
        }
    })
};
//promise.finally 无论成功或者失败都会执行，如果finally中返回了一个promise会等待这个promise执行完成后继续执行
Promise.resolve(1000)
    .finally(() => {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                resolve("hello");
            });
        }, 1000);
    })
    .then(
        (data) => {
            console.log("success" + data); //data输出不是hello而是上一级结果1000
        },
        (fail) => {
            console.log("error" + fail);
        }
    );

Promise.prototype.finally = function (cb) {
    return this.then(
        (value) => {
            return Promise.resolve(cb()).then(() => value);
        },
        (err) => {
            return Promise.resolve(cb()).then(() => {
                throw err;
            });
        }
    );
};

//promise.reslove / promise.reject /resolve会等待里面的promise执行成功 而reject不会
/**
 * 1.传参为一个 Promise, 则直接返回它。
 * 2.传参为一个 thenable 对象，返回的 Promise 会跟随这个对象，采用它的最终状态作为自己的状态。
 * 3.其他情况，直接返回以该值为成功状态的promise对象。
 */
Promise.resolve = function (param) {
    if (param instanceof Promise) return param;
    return new Promise((resolve, reject) => {
        if (param && param.then && typeof param.then === "function") {
            // param 状态变为成功会调用resolve，将新 Promise 的状态变为成功，反之亦然
            param.then(resolve, reject);
        } else {
            resolve(param);
        }
    });
};

Promise.reject = function (value) {
    return new Promise((resolve, reject) => {
        reject(value);
    });
};
//generator

function* gen() {
    yield 1;
    yield 2;
}
let it = gen();
console.log(it.next());
